#include "BaseParser.h"

BaseParser::BaseParser(const QString& filename, BaseLoader& loader)
    : _loader(loader)
{
    QFile file(filename);
    QXmlInputSource src(&file);

    QXmlSimpleReader reader;
    reader.setContentHandler(this);

    if (!reader.parse(src)) {
        cout << "Nao foi possivel realizar o parse do arquivo" << endl;
        throw -1;
    }
}

QString BaseParser::_generatePath(QList<QString> & v)
{
    QString s;
    for (QList<QString>::iterator i = v.begin(); i != v.end(); i++) {
        s.append('/');
        s.append(*i);
    }
    return s;
}

void BaseParser::setDocumentLocator(QXmlLocator* locator)
{

}

bool BaseParser::startDocument()
{
    _path.clear();
    _pathMap.clear();
    _ancestor.clear();
    _completePath.clear();

    clock_gettime(CLOCK_MONOTONIC, &_startTime);
    _numOfElements = 0;
    _maxValueTextSize = 0;
    _maxPathTextSize = 0;
    _maxDepth = 0;
    return true;
}

bool BaseParser::endDocument()
{
    for (PathMap::iterator it = _pathMap.begin()++; it != _pathMap.end(); it++)
        _loader.addPathElement(it.key(), it.value());

    clock_gettime(CLOCK_MONOTONIC, &_endTime);

    quint64 acBufferSize,
        acNumberQueries;
    uint numOfDbAccess;


    _loaderTime = _loader.getAdditionalTime() + timespecToMilisecond(_endTime) - timespecToMilisecond(_startTime);
/*
    _loader.getFinalData(acBufferSize, acNumberQueries, numOfDbAccess);

    cout << "ms " << (uint) timespecToMilisecond(_endTime) - timespecToMilisecond(_startTime) << " "; // tempo de processamento em ms
    cout << "bd_access " << numOfDbAccess << " "; // numero de acessos ao banco de dados
    cout << "avg_buffer_size " << acBufferSize / numOfDbAccess << " "; // média do tamanho da string de consulta
    cout << "num_queries " << acNumberQueries << " "; // numero total de consultas
    cout << "avg_queries_per_access " << acNumberQueries / numOfDbAccess << " "; // média do número de consultas em cada acesso ao banco
    cout << "num_of_elements " << _numOfElements << " "; // número total de elementos inseridos (contando atributos)
    cout << "num_paths " << _pathMap.count() << " "; // numero de caminhos
    cout << "max_value_text_size " << _maxValueTextSize << " "; // tamanho mínimo para a coluna de texto
    cout << "max_path_text_size " << _maxPathTextSize << " ";
    cout << "max_depth " << _maxDepth << " ";
    cout << endl;
*/
    return true;
}

bool BaseParser::startPrefixMapping(const QString& prefix, const QString& uri)
{
    return true;
}

bool BaseParser::endPrefixMapping(const QString& prefix)
{
    return true;
}

uint BaseParser::_addPath(const QString& localName)
{
    _path.push_back(localName);
    _completePath = _generatePath(_path);

    if (_path.size() > _maxDepth)
        _maxDepth = _path.size();
    if (_completePath.size() > _maxPathTextSize)
        _maxPathTextSize = _completePath.size();

    PathMap::iterator it = _pathMap.find(_completePath);
    if (it == _pathMap.end()) {
        uint path_id = _pathMap.size();
        _pathMap.insert(_completePath,path_id);
        return path_id;
    } else {
        return it.value();
    }
}

bool BaseParser::startElement(const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts)
{
    uint path_id = _addPath(localName);

    _ancestor.push_back(_loader.newElement(_ancestor.isEmpty() ? NULL : _ancestor.last(), ++_numOfElements, "", path_id, false));

    for (int i = 0; i < atts.length(); ++i) {
        path_id = _addPath(atts.localName(i));
        _ancestor.push_back(_loader.newElement(_ancestor.last(), ++_numOfElements, atts.value(i), path_id, true));
        // chama o endElement pra inserir direto o atributo
        if (!endElement("", "", ""))
            return false;
    }

    return true;
}

bool BaseParser::endElement(const QString& namespaceURI, const QString& localName, const QString& qName)
{
    EdgeElement* e = _ancestor.last();
    uint end_desc_id = e->end_desc_id;

    if (!_loader.addEdgeElement(*e))
        return false;
    _ancestor.pop_back();
    // desaloca o elemento
    delete e;
    _path.pop_back();

    if (!_ancestor.empty())
        _ancestor.last()->end_desc_id = end_desc_id;
    return true;
}

bool BaseParser::characters(const QString& ch)
{
    QString tmp(ch.trimmed());
    _ancestor.last()->value.append(tmp);

    if (tmp.size() > _maxValueTextSize)
        _maxValueTextSize = tmp.size();

    return true;
}

bool BaseParser::ignorableWhitespace(const QString& ch)
{
    return true;
}

bool BaseParser::processingInstruction(const QString& target, const QString& data)
{
    return true;
}

bool BaseParser::skippedEntity(const QString& name)
{
    return true;
}

QString BaseParser::errorString() const
{
    return QString("Error!!!");
}
